﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Wheels
{
    public partial class PublishingCollection<T>
      : ThreadSafeDisposable
    {
#pragma warning disable 1591

        // Here comes MAGIC! DO NOT TOUCH if you have no clue about memory model and/or volatile read/write

        private volatile Holder mTopHolder;

        #region 构造与消解

        /// <summary>
        /// 创建一个面向指定类型的 PublishingCollection。
        /// </summary>
        public PublishingCollection()
        {
            mTopHolder = new Holder(default(T));
        }

        /// <summary>
        /// 释放由此对象使用的资源，可以只释放非托管资源或者连同托管资源一并释放。
        /// </summary>
        /// <param name="disposing">指示是否释放非托管资源。</param>
        protected override void Dispose(bool disposing)
        {
#pragma warning disable 0420
            // 不仅需要置空，还需要确保资源已经得到正确释放。
            var holder = Interlocked.Exchange(ref mTopHolder, null);
#pragma warning restore 0420

            // 终结器, 不应调用 holder.Dispose()
            if (!disposing) return;

            if (null != holder)
            {
                holder.Dispose();
            }
        }

        #endregion

        #region 读写

        public void Push(T data)
        {
            // 由于只存在旧 Holder 指向新 Holder 的单向引用，所以新建 Holder 只需要携带数据，而在以后新建的 Holder 出现之前不需要进行任何改变。
            // 然而由于要保障数据的连续性，所以当有多个线程竞争的时候必须有机制保证只有目前最新的 Holder 会指向此处新建的 Holder。

            var newTop = new Holder(data);
            // 对 mTopHolder 的读取操作具有 acquire 语义
            var top = mTopHolder;

            // 只要 top 不为 null 就反复进行尝试
            while (null != top)
            {
#pragma warning disable 0420
                // 只有当 mTopHolder 的当前状态和 top 等同的时候才能进行替换。
                var currentTop = Interlocked.CompareExchange(ref mTopHolder, newTop, top);
#pragma warning restore 0420

                // 若状态未发生变化则可确定操作成功，那么只要对前一个 Holder 进行配置就大功告成了。
                if (currentTop == top)
                {
                    // HACK: may be depending on CLR implemention
                    top.SetNext(newTop);
                    return;
                }

                // 若 mTopHolder 的状态已经发生了改变，则通过循环来重新检查。
                top = currentTop;
            }

            // 运行到此处则说明由于进行了消解操作而导致 mTopHolder 为空。
            newTop.Dispose();
            throw new ObjectDisposedException("PublishingCollection");
        }

        #region 枚举读

        class EnumMe
        {
            public Holder Current;

            private IEnumerable<T> mEnumerable;
            public IEnumerable<T> Enumerable
            {
                get
                {
                    if (mEnumerable == null)
                    {
                        mEnumerable = MakeEnumerable();
                    }
                    return mEnumerable;
                }
            }

            IEnumerable<T> MakeEnumerable()
            {
                if (Current != null)
                    Current = Current.GetNext();
                for (; Current != null; Current = Current.GetNext())
                {
                    yield return Current.Data;
                }
            }
        }

        public IEnumerable<T> GetSubscriberEnumerable()
        {
            // 对 mTopHolder 的读取操作具有 acquire 语义
            // HACK: 需避免使 mTopHolder 的内容（一个对象引用）驻留在任何方法的作用域中，因而不使用参数传递的形式
            return new EnumMe { Current = mTopHolder }.Enumerable;
        }

        #endregion

        #endregion
    }

}
